// OutpatientRefundPanel.java 门诊退费界面
package com.dw.gui.panel.fee;


import com.dw.dao.fee.ChargeRecordDao;
import com.dw.dao.fee.RefundRecordDao;
import com.dw.dao.invoice.InvoiceDao;
import com.dw.dao.user.PatientDao;
import com.dw.model.fee.ChargeRecord;
import com.dw.model.fee.RefundRecord;
import com.dw.model.invoice.Invoice;
import com.dw.model.user.Doctor;
import com.dw.util.DBUtil;
import com.dw.util.UIUtil;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.math.BigDecimal;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;
import java.util.Objects;

public class OutpatientRefundPanel extends JPanel {
    private final Doctor doctor;
    private JComboBox<String> cbChargeNo; // 改为下拉框
    private JLabel lblPatientInfo;
    private JLabel lblOriginalAmount;
    private JTextField tfRefundAmount;
    private JTextArea taReason;

    private final ChargeRecordDao chargeDao = new ChargeRecordDao();
    private final InvoiceDao invoiceDao = new InvoiceDao();
    private final RefundRecordDao refundDao = new RefundRecordDao();

    public OutpatientRefundPanel(Doctor doctor) {
        this.doctor = doctor;
        initUI();
        loadChargeNumbers();
    }

    private void initUI() {
        setLayout(new BorderLayout(10, 10));
        setBackground(Color.WHITE);

        // 标题面板
        JPanel titlePanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
        titlePanel.setBackground(Color.WHITE);
        titlePanel.add(UIUtil.createTitleLabel("门诊退费"));
        titlePanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));

        // 主表单面板（使用GridBagLayout）
        JPanel formPanel = new JPanel(new GridBagLayout());
        formPanel.setBackground(Color.WHITE);
        formPanel.setBorder(BorderFactory.createTitledBorder("退费信息"));
        GridBagConstraints gbc = new GridBagConstraints();
        gbc.insets = new Insets(5, 5, 5, 5);
        gbc.anchor = GridBagConstraints.WEST;
        gbc.fill = GridBagConstraints.HORIZONTAL;

        // 原收费单号行（第0行）
        gbc.gridx = 0;
        gbc.gridy = 0;
        formPanel.add(UIUtil.createLabel("原收费单号："), gbc);

        gbc.gridx = 1;
        JPanel searchPanel = new JPanel(new BorderLayout(5, 0));
        cbChargeNo = UIUtil.createComboBox(new String[] {}); // 创建下拉框
        cbChargeNo.setPreferredSize(new Dimension(200, 25));
        JButton btnSearch = UIUtil.createButton("查询");
        btnSearch.setPreferredSize(new Dimension(80, 25));
        btnSearch.addActionListener(this::searchCharge);
        searchPanel.add(cbChargeNo, BorderLayout.CENTER);
        searchPanel.add(btnSearch, BorderLayout.EAST);
        formPanel.add(searchPanel, gbc);

        // 患者信息行（第1行）
        gbc.gridx = 0;
        gbc.gridy = 1;
        formPanel.add(UIUtil.createLabel("患者信息："), gbc);

        gbc.gridx = 1;
        lblPatientInfo = UIUtil.createLabel("");
        lblPatientInfo.setBorder(BorderFactory.createLineBorder(Color.GRAY));
        lblPatientInfo.setPreferredSize(new Dimension(200, 25));
        formPanel.add(lblPatientInfo, gbc);

        // 原收费金额行（第2行）
        gbc.gridx = 0;
        gbc.gridy = 2;
        formPanel.add(UIUtil.createLabel("原收费金额："), gbc);

        gbc.gridx = 1;
        lblOriginalAmount = UIUtil.createLabel("");
        lblOriginalAmount.setBorder(BorderFactory.createLineBorder(Color.GRAY));
        lblOriginalAmount.setPreferredSize(new Dimension(200, 25));
        formPanel.add(lblOriginalAmount, gbc);

        // 退费金额行（第3行）
        gbc.gridx = 0;
        gbc.gridy = 3;
        formPanel.add(UIUtil.createLabel("退费金额："), gbc);

        gbc.gridx = 1;
        tfRefundAmount = UIUtil.createTextField();
        tfRefundAmount.setPreferredSize(new Dimension(200, 25));
        formPanel.add(tfRefundAmount, gbc);

        // 退费原因行（第4行）
        gbc.gridx = 0;
        gbc.gridy = 4;
        formPanel.add(UIUtil.createLabel("退费原因："), gbc);

        gbc.gridx = 1;
        gbc.fill = GridBagConstraints.BOTH;
        gbc.weighty = 1.0; // 分配额外垂直空间
        taReason = UIUtil.createTextArea(3, 20);
        JScrollPane scrollPane = new JScrollPane(taReason);
        scrollPane.setPreferredSize(new Dimension(300, 80));
        formPanel.add(scrollPane, gbc);

        // 操作按钮面板
        JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 20, 10));
        buttonPanel.setBackground(Color.WHITE);

        JButton btnRefund = UIUtil.createButton("执行退费");
        btnRefund.setPreferredSize(new Dimension(120, 30));
        btnRefund.addActionListener(this::performRefund);

        JButton btnReset = UIUtil.createButton("重置");
        btnReset.setPreferredSize(new Dimension(120, 30));
        btnReset.addActionListener(e -> resetForm());

        buttonPanel.add(btnRefund);
        buttonPanel.add(btnReset);

        // 组装主界面
        JPanel mainPanel = new JPanel(new BorderLayout(10, 10));
        mainPanel.setBackground(Color.WHITE);
        mainPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
        mainPanel.add(formPanel, BorderLayout.CENTER);
        mainPanel.add(buttonPanel, BorderLayout.SOUTH);

        add(titlePanel, BorderLayout.NORTH);
        add(mainPanel, BorderLayout.CENTER);
    }

    private void loadChargeNumbers() {
        new SwingWorker<List<String>, Void>() {
            @Override
            protected List<String> doInBackground() throws Exception {
                return new ChargeRecordDao().getAllChargeNos();
            }

            @Override
            protected void done() {
                try {
                    DefaultComboBoxModel<String> model = new DefaultComboBoxModel<>();
                    get().forEach(model::addElement);
                    cbChargeNo.setModel(model);
                } catch (Exception e) {
                    UIUtil.showError(OutpatientRefundPanel.this,
                            "加载收费单号失败：" + e.getMessage(), "数据错误");
                }
            }
        }.execute();
    }

    private void searchCharge(ActionEvent e) {
        try {
            String selectedNo = (String) cbChargeNo.getSelectedItem();
            ChargeRecord record = new ChargeRecordDao().getByChargeNo(selectedNo);

            if (record == null) {
                UIUtil.showError(this, "收费记录不存在", "查询失败");
                return;
            }

            String patientInfo = new PatientDao().findById(record.getPatientId()).getName();
            lblPatientInfo.setText(patientInfo);
            lblOriginalAmount.setText(record.getAmount() + " 元");
            tfRefundAmount.requestFocus();
        } catch (Exception ex) {
            UIUtil.showError(this, "查询失败：" + ex.getMessage(), "系统错误");
        }
    }

    private void performRefund(ActionEvent e) {
        try {
            // 获取输入参数
            String chargeNo = (String) cbChargeNo.getSelectedItem();
            BigDecimal refundAmount = new BigDecimal(tfRefundAmount.getText().trim());
            String reason = taReason.getText().trim();

            // 空值校验
            if (chargeNo == null || chargeNo.isEmpty()) {
                throw new IllegalArgumentException("请选择收费单号");
            }
            if (reason.isEmpty()) {
                throw new IllegalArgumentException("退费原因不能为空");
            }

            // 执行退费
            processRefund(
                    chargeNo,
                    refundAmount,
                    doctor.getId(),  // 使用当前医生ID
                    reason
            );

            UIUtil.showInfo(this, "退费成功", "操作结果");
            resetForm();
        } catch (NumberFormatException ex) {
            UIUtil.showError(this, "金额格式不正确", "输入错误");
        } catch (IllegalArgumentException ex) {
            UIUtil.showError(this, ex.getMessage(), "数据校验失败");
        } catch (Exception ex) {
            UIUtil.showError(this, "退费失败：" + ex.getMessage(), "系统错误");
        }
    }

    private void resetForm() {
        cbChargeNo.setSelectedIndex(-1);
        lblPatientInfo.setText("");
        lblOriginalAmount.setText("");
        tfRefundAmount.setText("");
        taReason.setText("");
    }

    public void processRefund(String chargeNo, BigDecimal refundAmount,
                              int operatorId, String reason) throws SQLException {
        Connection conn = null;
        try {
            conn = DBUtil.getConnection();
            conn.setAutoCommit(false);

            // 获取原记录并验证
            ChargeRecord original = chargeDao.getByChargeNoWithLock(conn, chargeNo);
            validateRefund(original, refundAmount);

            // 更新原记录状态
            chargeDao.updateStatus(conn, chargeNo, "已退费");

            // 创建退费记录
            RefundRecord refund = createRefundRecord(original, refundAmount, operatorId, reason);
            refundDao.create(conn, refund);

            // 作废关联发票
            Invoice relatedInvoice = invoiceDao.getByChargeNo(chargeNo);
            if(relatedInvoice != null) {
                invoiceDao.voidInvoice(relatedInvoice.getId(), operatorId, reason);
            }

            conn.commit();
        } catch (SQLException e) {
            if (conn != null) conn.rollback();
            throw e;
        } finally {
            if (conn != null) conn.close();
        }
    }

    private void validateRefund(ChargeRecord record, BigDecimal amount) {
        if(record == null) {
            throw new IllegalArgumentException("收费记录不存在");
        }
        if(!"正常".equals(record.getStatus())) {
            throw new IllegalArgumentException("该记录已退费，不可重复操作");
        }
        if(amount.compareTo(record.getAmount()) > 0) {
            throw new IllegalArgumentException("退费金额超过原金额");
        }
        if(amount.compareTo(BigDecimal.ZERO) <= 0) {
            throw new IllegalArgumentException("退费金额必须大于零");
        }
    }

    private RefundRecord createRefundRecord(ChargeRecord original, BigDecimal amount,
                                            int operatorId, String reason) {
        RefundRecord refund = new RefundRecord();
        refund.setChargeNo(original.getChargeNo());
        refund.setRefundAmount(amount);
        refund.setOperatorId(operatorId);
        refund.setReason(reason);
        return refund;
    }
}